[Swift]WKWebViewで長押しによるメニュー表示を止める
CX事業本部の中安です。まいどです。
本日はiOSアプリ開発の小ネタになりますが、WKWebView
で「長押しによるメニュー表示を止める方法」を書き留めたいと思います。
iPhone や iPad を使っている方ならよく使うと思いますが、 ブラウザ上の文字を長押しすると、下図のようにPCでいうところの右クリックのように範囲選択してコピー等をするためのメニューが表示されます。
これはWKWebView
。つまり、アプリ上のWEBビューでも同じ動作をします。
しかし、アプリによってはこのメニュー表示をさせたくないこともあるかもしれません。 今回は、このメニュー表示を制御してみることにしましょう。
前提となる実装
今記事ではUI実装については割愛しますが、
今回作る画面(名前をWebViewController
とします)では WKWebView
が画面全体に配置されているものとします。
その場合の必要最低限な実装は以下のような感じです。
import UIKit import WebKit class WebViewController: UIViewController { @IBOutlet private weak var webView: WKWebView! override func viewDidLoad() { super.viewDidLoad() let url = URL(string: "URLがここに入る")! let request = URLRequest(url: url) webView.load(request) } }
ちなみに今記事では "URLがここに入る"
には、https://ja.wikipedia.org/wiki/Swift_(%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E8%A8%80%E8%AA%9E) という Wikipedia の記事を入れています。
メニュー表示を止める仕組み
前項の実装のままであると、最初に書いたように長押しすることでメニューが表示されてしまいます。
これを止めるにはJavascript
とCSS
の仕組みを使用します。
読み込まれたHTMLドキュメントのヘッダに対して、Javascript を使って style要素を後から足してやるという方法です。
そのstyle
要素に操作制御系のCSS
を書いてやることで実現をしていきます。
では、ここに足していくべき操作制御系のCSS
プロパティをご紹介します。
-webkit-user-select
The user-select CSS property controls whether the user can select text. This doesn't have any effect on content loaded as part of a browser's user interface (its chrome), except in textboxes.
user-select CSSプロパティは、ユーザーがテキストを選択可能かどうかをコントロールします。これは、テキストボックスを除き、ブラウザUI(Chrome)の一部として読み込まれるコンテンツに影響を与えません。
user-select
の中でも-webkit-user-select
はsafari
エンジンのブラウザ解釈に影響を与えます。
ですので、今回は-webkit-user-select
プロパティを使用していきます。
https://developer.mozilla.org/en/docs/Web/CSS/user-select
-webkit-touch-callout
The -webkit-touch-callout CSS property controls the display of the default callout shown when you touch and hold a touch target.
When a target is touched and held on iOS, Safari displays a callout information about the link. This property allows disabling that behavior.
-webkit-touch-callout CSSプロパティは、タッチターゲットを長押したときに表示されるデフォルトのコールアウト表示をコントロールします。
iOSでターゲットを長押しすると、Safariはリンクに関するコールアウト情報を表示します。 このプロパティは、その振る舞いを無効化できます。
ドキュメントによると、CSSとしては非標準ではありますが、iOSブラウザ上の制御のために用意されているCSSプロパティのようです。
「リンクに関するコールアウト情報」というのは、リンクを長押しした時に出る下図のような「プレビュー表示」と呼ばれるものです。
長押しでのメニューを非表示にするならば、このプレビュー表示(コールアウト表示)も制御しておきたいところです。
https://developer.mozilla.org/en/docs/Web/CSS/-webkit-touch-callout
extensionを定義
では、WKWebView
に対して以下のような extension を用意しましょう。
extension WKWebView { /// 長押しによる選択、コールアウト表示を禁止する func prohibitTouchCalloutAndUserSelect() { let script = """ var css = '*{-webkit-touch-callout:none;-webkit-user-select:none}'; var head = document.head || document.getElementsByTagName('head')[0]; var style = document.createElement('style'); style.type = 'text/css'; style.appendChild(document.createTextNode(css)); head.appendChild(style); """ evaluateJavaScript(script, completionHandler: nil) } }
前項でも述べたとおり、CSS
を<head>
タグに埋め込むためのJavascript
をWEBビューに対して呼ばせます。
当ブログの仕様上、シンタックスハイライトが上手くいかないのですが、
上のコードで明るくハイライトしている部分はすべて Swift上では文字列となり、Javascript
のソースコードになります。
その部分だけ切り出してみましょう。以下はSwift
ではくJavascript
として読んでくださいね。
var css = '*{-webkit-touch-callout:none;-webkit-user-select:none}'; var head = document.head || document.getElementsByTagName('head')[0]; var style = document.createElement('style'); style.type = 'text/css'; style.appendChild(document.createTextNode(css)); head.appendChild(style);
HTMLのすべての要素に対して、先ほどのCSSプロパティをnone
で指定していることがわかると思います。
適用する
最初に書いた前提となる実装コードに、今回の処理を適用してみましょう。
import UIKit import WebKit class WebViewController: UIViewController { @IBOutlet private weak var webView: WKWebView! override func viewDidLoad() { super.viewDidLoad() webView.navigationDelegate = self let url = URL(string: "URLがここに入る")! let request = URLRequest(url: url) webView.load(request) } } extension WebViewController: WKNavigationDelegate { func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { webView.prohibitTouchCalloutAndUserSelect() } }
明るくハイライトしたのが追記した部分になります。
このようにドキュメントが読み終わった時に、ドキュメントに対してCSSを追加することでメニュー表示を制御することができます。
アプリを起動して実際に長押しして確認してみてください。
最後に
この方法は、HTMLに対して要素を追加することで実現しているので、 例えばプレーンテキストであったり、その他HTML以外のドキュメントに対しては制御できないと思います。
また、WEBページによっては制御が効かない場合もあるかもしれません。 (数多くのWEBページで検証をしたわけではありません)
WEBビューに表示するコンテンツ要件などを検討のもと、 用途に合致しそうであればお試しいただければと思います。
それでは、また。